#ifndef PIPES_H
#define PIPES_H

#include <termios.h>
#include <stdio.h>
#include <limits.h>

#ifndef BOOL
#define BOOL int
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define ALLOC                   // indicate that a memory which should be freed after using
//#define SPACE                   // indicate that a memory which is enough to use
#define MANAGED                 // indicate that a memory which is managed inside the function or object

#include <unistd.h>

enum eCommandKind { 
    kJobs, 
    kFg,
    kExit,
    kGCInfo,
    kStackInfo,
    kSweep,
    kSubshell,
    kIf,
    kWhile,
    kBreak,
    kReturn,
    kPrint,
    kRehash,
    kTrue,
    kFalse,
    kDef,
    kVar,
    kWrite,
    kQuote,
    kLoad,
    kEach,
    kInherit,
    kEval,
    kObject,
    kPwo,
    kCo,
    kRef,
    kClass,
    kAry,
    kHash,
    kLength,
    kExport,
    kX,

    kInnerCommand,
    kCommand,
    kCommandMax
};

typedef void (*fFreeFun)(void*);
typedef int (*fMarkFun)(void*);

typedef struct _list_it {
   void* mItem;
   
   struct _list_it* mPrevIt;
   struct _list_it* mNextIt;
} list_it;

typedef struct {
   list_it* mEntryIt;
   list_it* mLastIt;
   int mCount;
} list_obj;

typedef struct _hash_it {
   char* mKey;
   
   void* mItem;
   struct _hash_it* mCollisionIt;

   struct _hash_it* mNextIt;
} hash_it;

enum eLineField { kLF, kCRLF, kCR, kBel };
extern enum eLineField gLineField;
extern enum eKanjiCode gKanjiCode;

typedef struct {
   hash_it** mTable;
   int mTableSize;

   hash_it* mEntryIt;

   int mCounter;
} hash_obj;

typedef struct
{
    char* mStr;
    int mLen;

    int mMallocLen;
} string_obj;

typedef struct {
   void** mTable;
   int mTableSize;
   
   int mCount;
} vector_obj;

/*
typedef struct {
   void** mTable;
   int mTableSize;
   
   int mCount;
} stackframes_obj;
*/

typedef struct {
    char* mBuf;
    int mBufSize;
    int mBufLen;

    struct _sObject* mLines;
    enum eLineField mLinesLineField;
} fd_obj;

typedef struct {
    char mPath[PATH_MAX];
} external_prog_obj;

struct sStatment;

#define STATMENT_REVERSE 0x01 
#define STATMENT_BACKGROUND 0x02
#define STATMENT_GLOBALPIPEIN 0x04
#define STATMENT_GLOBALPIPEOUT 0x08
#define STATMENT_CONTEXTPIPE 0x10
#define STATMENT_NORMAL 0x20
#define STATMENT_OROR 0x40
#define STATMENT_ANDAND 0x80

#define STATMENT_COMMANDS_MAX 32
#define STATMENT_OPTIONS_MAX 8
#define STATMENT_OPTION_STRING_MAX 32

struct block_obj;
struct _sObject;

typedef struct _option_hash_it {
    char* mKey;
    char* mArg;
} option_hash_it;

#define PIPES_OPTION_MAX 32
#define PIPES_MESSAGES_MAX 16

enum eEnvKind { kEnv, kEnvBlock};

typedef struct {
    enum eEnvKind mKind;
    union {
        struct {
            char* mName;
            char* mKey;
            BOOL mKeyEnv;
        };
        struct {
            struct _sObject* mBlock;
            enum eLineField mLineField;
        };
    };
} sEnv;

typedef struct {
    enum eCommandKind mKind;

    char** mArgs;
    int* mArgsEnv;    // This index is the same as mArgs, it's true when the variable in the argument will be expanded.
    int mArgsNum;
    int mArgsSize;

    char** mArgsRuntime;
    int mArgsNumRuntime;
    int mArgsSizeRuntime;

    sEnv* mEnvs;
    int mEnvsNum;
    int mEnvsSize;

    struct _sObject** mBlocks;     // block_obj**
    int mBlocksNum;
    int mBlocksSize;

    option_hash_it mOptions[PIPES_OPTION_MAX];  // open adressing hash

    char* mMessages[PIPES_MESSAGES_MAX];
    int mMessagesNum;
} sCommand;

typedef struct {
    sCommand mCommands[STATMENT_COMMANDS_MAX];
    int mCommandsNum;

    char* mFName;
    int mLine;

    int mFlags;
} sStatment;

#define COMPLETION_FLAGS_LAST_CHAR_IS_SPACE 0x0100
#define COMPLETION_FLAGS_LAST_CHAR_IS_PIPE 0x0200
#define COMPLETION_FLAGS_ENV 0x0800
#define COMPLETION_FLAGS_ENV_BLOCK 0x1000
#define COMPLETION_FLAGS_BLOCK 0x2000
#define COMPLETION_FLAGS_TILDA 0x4000

struct block_obj
{
    sStatment* mStatments;
    int mStatmentsNum;
    int mStatmentsSize;
    char* mSource;
    int mCompletionFlags;
};

struct _sObject;
struct _sRunInfo;

typedef struct                // a function object can be treated as block_obj
{
    sStatment* mStatments;
    int mStatmentsNum;
    int mStatmentsSize;
    char* mSource;

    struct _sObject* mParent;
    int mParentCount;

    struct _sObject* mLocalObjects;
    struct _sObject* mArgBlocks;

    option_hash_it mOptions[PIPES_OPTION_MAX];
    struct _sRunInfo* mRunInfo;
} fun_obj;

typedef BOOL (*fNativeFun)(struct _sObject*, struct _sObject*, struct _sRunInfo*);

typedef struct 
{
    fNativeFun mNativeFun;
    struct _sObject* mParent;

    option_hash_it mOptions[PIPES_OPTION_MAX];
} nfun_obj;

typedef struct {
    char* mName;                // the job name
    pid_t mPGroup;              // process group id
    struct termios mTty;        // a terminal status
    BOOL mSuspended;
} job_obj;

typedef struct {                // a user object can be treated like a hash_obj
   hash_it** mTable;
   int mTableSize;

   hash_it* mEntryIt;

   int mCounter;

   char* mName;

   struct _sObject* mParent;
} uobject_obj;

typedef struct _memchecker_it {
   void* mKey;
   
   int mItem;
   struct _memchecker_it* mCollisionIt;

   struct _memchecker_it* mNextIt;
} memchecker_it;

typedef struct {
   memchecker_it** mTable;
   int mTableSize;

   memchecker_it* mEntryIt;

   int mCounter;
} memchecker_obj;

typedef int (*fExtObjMarkFun)(struct _sObject* self);
typedef void (*fExtObjFreeFun)(void* self);

typedef struct {
    void* mObject;
    fExtObjMarkFun mMarkFun;
    fExtObjFreeFun mFreeFun;
} external_obj;

#define GC_MARK 0x80000000

#define T_STRING 1
#define T_VECTOR 2
#define T_HASH 3
#define T_LIST 4
#define T_NFUN 5
#define T_BLOCK 6
#define T_FD 7
#define T_JOB 8
#define T_UOBJECT 9
#define T_MEMCHECKER 10
#define T_FUN 11
#define T_CLASS 12
#define T_EXTERNAL 13
#define T_COMPLETION 14
#define T_EXTOBJ 15

typedef struct _sObject {
    int mFlg;                         // contains a kind of the above and a mark flag
    struct _sObject* mNextFreeObject;
    BOOL mUserObject;

    union {
        string_obj uString;
        vector_obj uVector;
        hash_obj uHash;
        list_obj uList;
        fd_obj uFd;
        job_obj uJob;
        struct block_obj uBlock;

        uobject_obj uUObject;
        memchecker_obj uMemchecker;
        nfun_obj uNativeFun;
        fun_obj uFunction;
        external_prog_obj uExternalProg;
        external_obj uExternalObj;
    };
} sObject;

#define TYPE(o) (o->mFlg & 0xFF)

#define SSTRING(o) (o)->uString
#define SVECTOR(o) (o)->uVector
#define SHASH(o) (o)->uHash
#define SLIST(o) (o)->uList
#define SBLOCK(o) (o)->uBlock
#define SNFUN(o) (o)->uNativeFun
#define SFD(o) (o)->uFd
#define SJOB(o) (o)->uJob
#define SUOBJECT(o) (o)->uUObject
#define SMEMCHECKER(o) (o)->uMemchecker
#define SFUN(o) (o)->uFunction
#define SEXTERNAL(o) (o)->uExternalProg
#define SEXTOBJ(o) (o)->uExternalObj

void gc_init(int pool_size);
void gc_final();
sObject* gc_get_free_object(int kind, BOOL user_object);

void stack_init(int stack_page_size);
void stack_final();
void stack_start_stack();
void stack_end_stack();
sObject* stack_get_free_object(int kind);
int stack_slot_size();
int stack_page_size();

#include "debug.h"
#include "hash.h"
#include "kanji.h"
#include "string.h"
#include "vector.h"
#include "list.h"
#include "block.h"
#include "curses.h"

sObject* extobj_new_from_gc(void* object, fExtObjMarkFun mark_fun, fExtObjFreeFun free_fun, BOOL user_object);
#define EXTOBJ_NEW_GC(o, o2, o3, o4) extobj_new_from_gc(o, o2, o3, o4)

sObject* uobject_new_from_gc(int size, sObject* parent, char* name, BOOL user_object);
sObject* uobject_new_from_stack(int size, sObject* object, char* name);
void uobject_init(sObject* self);
void uobject_root_init(sObject* self);

#define UOBJECT_NEW_GC(o, o2, o3, o4) uobject_new_from_gc(o, o2, o3, o4)
#define UOBJECT_NEW_STACK(o, o2, o3) uobject_new_from_stack(o, o2, o3)

void uobject_delete_gc(sObject* self);
void uobject_delete_stack(sObject* self);
int uobject_gc_children_mark(sObject* self);

sObject* external_new_from_gc(char* path, BOOL user_object);
sObject* external_delete_gc();

#define EXTERNAL_NEW_GC(o, o2) external_new_from_gc(o, o2)

//sObject* stackframes_new_from_gc(int first_size, BOOL user_object);
//void stackframes_delete_gc(sObject* self);
//#define STACKFRAMES_NEW_GC(size, user_object) stackframes_new_from_gc(size, user_object)

/// structure used from run, which contains run time info
typedef struct _sRunInfo {
    char* mSName;
    int mSLine;
    int mRCode;
    sCommand* mCommand;
    sStatment* mStatment;
    BOOL mLastProgram;
    int mNestLevel;
    BOOL mFilter;
    sObject* mCurrentObject;
    sObject* mRunningObject;
    sObject* mRecieverObject;
} sRunInfo;

typedef BOOL (*fInternalCommand)(sObject*, sObject*, sRunInfo*);

extern fInternalCommand kInternalCommands[kInnerCommand];
extern char * gCommandKindStrs[kCommandMax];

BOOL pipes_rehash(char* sname, int sline);

#if defined(HAVE_MIGEMO_H)
BOOL cmd_migemo_match(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
#endif
BOOL cmd_funinfo(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_readline_point_move(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_readline(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_readline_clear_screen(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_readline_insert_text(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_fselector(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_readline_delete_text(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_mshow(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_mrun(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_errmsg(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_prompt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_completion(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_try(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_rehash(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_sort(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_unset(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_p(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_selector(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_plusplus(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_minusminus(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_plus(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_minus(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_mult(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_div(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_mod(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_pow(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_abs(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_add(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_del(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_stackframe(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_jobs(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_gcinfo(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_stackinfo(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_fg(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_exit(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_sweep(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_subshell(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_print(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_if(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_break(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_while(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_return(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_rehash(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_true(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_false(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_def(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_var(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_write(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_quote(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_load(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_each(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_inherit(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_eval(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_object(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_pwo(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_co(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_ref(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_class(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_ary(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_hash(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_length(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_export(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_x(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_msleep(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_raise(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_cd(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_popd(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_pushd(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_block(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_index(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_rindex(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_uc(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_lc(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_chomp(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_chop(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_pomch(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_printf(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_join(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_lines(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_rows(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_scan(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_split(sObject* nextin, sObject* nextout, sRunInfo* runinfo);

BOOL cmd_condition_n(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_z(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_b(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_c(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_d(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_f(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_h(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_l(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_p(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_t(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_s2(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_g(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_k(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_u(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_r(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_w(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_x(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_o(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_g2(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_e(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_s(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_eq(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_neq(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_slt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_sgt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_sle(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_sge(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_eq2(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_ne(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_lt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_le(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_gt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_ge(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_nt(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_ot(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_ef(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_condition_re(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_sub(sObject* nextin, sObject* nextout, sRunInfo* runinfo);
BOOL cmd_time(sObject* nextin, sObject* nextout, sRunInfo* runinfo);

enum eAppType { kATOptC, kATXApp, kATConsoleApp };
    // Application kind

extern enum eAppType gAppType;

void pipes_init(enum eAppType app_type, BOOL no_runtime_script);
void pipes_final();

void run_init(enum eAppType app_type);
void run_final();

BOOL run(sObject* block, sObject* pipein, sObject* pipeout, int* rcode, sObject* current_object, sObject* running_object);
BOOL pipes(sObject* block, int* rcode);

sObject* fd_new_from_stack();
void fd_delete_stack(sObject* self);
#define FD_NEW_STACK() fd_new_from_stack()
BOOL fd_write(sObject* self, char* str);
BOOL fd_write3(sObject* self, char* str, int size);

sObject* job_new_from_gc(char* name, pid_t pgroup, struct termios tty);
#define JOB_NEW_GC(o, o2, o3) job_new_from_gc(o, o2, o3)
void job_delete_gc(sObject* self);
void job_push_back_child_pid(sObject* self, pid_t pid);

extern sObject* gErrMsg;               // error message

extern sObject* gStdin;
extern sObject* gStdout;
extern sObject* gStderr;

extern volatile BOOL gPipesSigInt;
extern volatile BOOL gPipesSigUser;

void pipes_restore_signal_default();
void pipes_set_signal();
void pipes_set_signal_optc();
void sigchld_block(int block);

extern void (*pipes_set_signal_other)();
extern void (*pipes_job_done)(int job_num, char* job_title);

BOOL forground_job(int num);
BOOL background_job(int num);
void pipes_wait_background_job();

void pipes_readline_init(BOOL runtime_script);
void pipes_readline_final();

extern sObject* gJobs;

int gc_free_objects_num();
int gc_slot_size();
int gc_pool_size();
int gc_used_objects_num();
int gc_sweep();

char* xstrncpy(char* src, char* des, int size);
char* xstrncat(char* src, char* des, int size);

BOOL parse(char* p, char* sname, int* sline, sObject* block, sObject** current_object, BOOL tilda_expand);
void tilda_expasion(char* file, ALLOC char** file2);

#define RCODE_BREAK 256
#define RCODE_RETURN 257
#define RCODE_EXIT 258
#define RCODE_SIGNAL_INTERRUPT 259
#define RCODE_NFUN_FALSE 260
#define RCODE_NFUN_INVALID_USSING 261
#define RCODE_NFUN_NULL_INPUT 262
//#define RCODE_COMMAND_NOT_FOUND 262

void pipes_kill_all_jobs();

extern sObject* gRootObject;
extern sObject* gCompletionObject;
extern sObject* gPipesObject;
extern sObject* gCurrentObject;
extern sObject* gObject;      // Object class object
extern sObject* gStackFrames;

BOOL bufsiz_write(int fd, char* buf);

BOOL load_file(char* fname, sObject* nextin, sObject* nextout, sRunInfo* runinfo, char** argv, int argc);
void pipes_load_file(char* fname, char** argv, int argc, BOOL no_runtime_script);
void pipes_opt_c(char* cmd, char** argv, int argc, BOOL no_runtime_script);
void pipes_readline_interface(char** argv, int argc, BOOL no_runtime_script);

void fd_split(sObject* self, enum eLineField lf);

void err_msg(char* msg, char* sname, int line, char* command);
void err_msg_adding(char* msg, char* sname, int line, char* command);

sObject* memchecker_new_from_stack(int size);
void memchecker_delete_stack(sObject* self);

#define MEMCHECKER_NEW_STACK(o) memchecker_new_from_stack(o)

void memchecker_put(sObject* self, void* key, int item);
BOOL memchecker_erase(sObject* self, void* key);
int memchecker_item(sObject* self, void* key);

int object_gc_children_mark(sObject* self);

sObject* nfun_new_from_gc(fNativeFun fun, sObject* parent, BOOL user_object);
#define NFUN_NEW_GC(o, o2, o3) nfun_new_from_gc(o, o2, o3)
int nfun_gc_children_mark(sObject* self);
void nfun_delete_gc(sObject* self);
BOOL nfun_put_option_with_argument(sObject* self, MANAGED char* key);
BOOL nfun_option_with_argument_item(sObject* self, char* key);

sObject* fun_new_from_gc(sObject* parent, BOOL user_object);
#define FUN_NEW_GC(o, o2) fun_new_from_gc(o, o2)
void fun_delete_gc(sObject* self);
int fun_gc_children_mark(sObject* self);
#define FUN_NEW_STACK(o) fun_new_from_stack(o)
sObject* fun_new_from_stack(sObject* parent);
void fun_delete_stack(sObject* self);
BOOL fun_put_option_with_argument(sObject* self, MANAGED char* key);
BOOL fun_option_with_argument_item(sObject* self, char* key);

sObject* class_new_from_gc(sObject* parent, BOOL user_object);
#define CLASS_NEW_GC(o, o2) class_fun_new_from_gc(o, o2)
void class_delete_gc(sObject* self);
void class_delete_stack(sObject* self);
BOOL class_option_with_argument_item(sObject* self, char* key);
BOOL class_put_option_with_argument(sObject* self, MANAGED char* key);


char* sCommand_option_with_argument_item(sCommand* self, char* key);
BOOL sCommand_put_option(sCommand* self, MANAGED char* key);
BOOL sCommand_put_option_with_argument(sCommand* self, MANAGED char* key, MANAGED char* argument);
BOOL sCommand_expand_env(sCommand* command, sObject* object, sObject* nextin, sObject* nextout, sRunInfo* runinfo);
void sCommand_sweep_runtime_info(sCommand* command);

extern sObject* gMemChecker;

extern FILE* gTest;

#define PIPES_INHERIT_MAX 32

sObject* access_object(char* name, sObject** current, sObject* running_object);
sObject* access_object2(char* name, sObject* current, sObject* running_object);
sObject* access_object3(char* name, sObject** current);

BOOL run_function(sObject* fun, sObject* nextin, sObject* nextout, sRunInfo* runinfo, char** argv, int argc, sObject** blocks, int blocks_num);

extern sObject* gDirStack;

#define PARSER_MAGIC_NUMBER_ENV 3
#define PARSER_MAGIC_NUMBER_OPTION 5

#include <oniguruma.h>
int get_onig_regex(regex_t** reg, sCommand* command, char* regex);

extern sObject* gPrompt;

extern sObject* gGlobalPipe;

#if defined(HAVE_MIGEMO_H)
void migemo_init();
void migemo_final();
#endif

int readline_signal();
void clear_matching_info_variable();

#endif
